﻿using FCSChart.Axis;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;

namespace FCSChart.Series
{
    public abstract class ISeries : FrameworkElement
    {
        #region property
        public string SeriesName { get; protected set; }
        #region 图形
        /// <summary>
        /// 填充色
        /// </summary>
        public Color Fill
        {
            get { return (Color)GetValue(FillProperty); }
            set { SetValue(FillProperty, value); }
        }
        public static readonly DependencyProperty FillProperty = DependencyProperty.Register("Fill", typeof(Color), typeof(ISeries), new PropertyMetadata(Helper.DefaultColor, (s, e) =>
        {
            if (s is ISeries series && e.NewValue is Color newcolor)
            {
                var geometries = series.Geometries.FirstOrDefault(p => p.Area == null);
                if (geometries != null)
                {
                    geometries.Fill = newcolor;
                    series.Drawing(series.Geometries);
                }
            }
        }));

        /// <summary>
        /// 笔的颜色
        /// </summary>
        public Color Stroke
        {
            get { return (Color)GetValue(StrokeProperty); }
            set { SetValue(StrokeProperty, value); }
        }
        public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register("Stroke", typeof(Color), typeof(ISeries), new PropertyMetadata(Colors.Transparent, (s, e) =>
        {
            if (s is ISeries series && e.NewValue is Color newcolor && series.Geometries != null)
            {
                var geometries = series.Geometries.FirstOrDefault(p => p.Area == null);
                if (geometries != null)
                {
                    geometries.Stroke = newcolor;
                    series.Drawing(series.Geometries);
                }
            }
        }));

        /// <summary>
        /// 笔的粗细
        /// </summary>
        public double Tickness
        {
            get { return (double)GetValue(TicknessProperty); }
            set { SetValue(TicknessProperty, value); }
        }
        public static readonly DependencyProperty TicknessProperty = DependencyProperty.Register("Tickness", typeof(double), typeof(ISeries), new PropertyMetadata(0d, (s, e) =>
        {
            if (s is ISeries series)
            {
                series.Drawing(series.Geometries);
            }
        }));

        /// <summary>
        /// 图形描述的集合
        /// </summary>
        protected List<StreamColor> Geometries { get; set; } = new List<StreamColor>();

        /// <summary>
        /// 计算图形的for循环时允许的最大并发线程数量
        /// </summary>
        public int MaxDegreeOfParallelism
        {
            get { return (int)GetValue(MaxDegreeOfParallelismProperty); }
            set { SetValue(MaxDegreeOfParallelismProperty, value); }
        }
        public static readonly DependencyProperty MaxDegreeOfParallelismProperty = DependencyProperty.Register("MaxDegreeOfParallelism", typeof(int), typeof(ISeries), new PropertyMetadata(4));


        #endregion

        /// <summary>
        /// 父容器
        /// </summary>
        public Chart OwnerChart { get; internal set; }
        protected readonly DrawingVisual DV;
        /// <summary>
        /// 获取渐变颜色的方法
        /// </summary>
        public Func<long, long, Color> GetGradientColor
        {
            get { return (Func<long, long, Color>)GetValue(GetGradientColorProperty); }
            set { SetValue(GetGradientColorProperty, value); }
        }
        public static readonly DependencyProperty GetGradientColorProperty = DependencyProperty.Register("GetGradientColor", typeof(Func<long, long, Color>), typeof(ISeries), new PropertyMetadata((s, e) => { if (s is ISeries series) series.Drawing(series.Geometries); }));

        #region 变形--用于缩放和移动，缩放图形容易变形，所以缩放改为重绘图形来实现
        Matrix Matrix;
        MatrixTransform MatrixTransform { get; set; }
        #endregion
        #endregion
        public ISeries()
        {
            GetGradientColor = Helper.GetGradientColor;
            DV = new DrawingVisual();
            this.AddVisualChild(DV);
            this.RenderTransform = MatrixTransform = new MatrixTransform(Matrix);
        }

        #region event
        /// <summary>
        /// 某些依赖属性改变后，需要重新绘制图形
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        protected static void NeedRedrawingProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is ISeries temp) temp.Drawing();
        }
        #endregion
        protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
        {
            base.OnRenderSizeChanged(sizeInfo);
            Drawing();
        }
        #region function
        /// <summary>
        /// 绘制图表界面
        /// </summary>
        /// <param name="items"></param>
        internal abstract void Drawing();

        internal virtual void Drawing(List<StreamColor> geometries)
        {
            if (geometries == null || geometries.Count <= 0)
            {
                if (DV != null)
                {
                    using (var dc = DV.RenderOpen())
                    {
                        ClearTransform();
                        dc.Close();
                    }
                }
                return;
            }
            var allg = geometries.Where(p => p.Area == null).ToList();
            var otherg = geometries.Where(p => p.Area != null && p.Area.OwnerGraphical != null && p.Area.OwnerGraphical.OwnerChart != this.OwnerChart).ToList();
            var myg = geometries.Where(p => p.Area != null && p.Area.OwnerGraphical != null && p.Area.OwnerGraphical.OwnerChart == this.OwnerChart).ToList();
            using (var dc = DV.RenderOpen())
            {
                ClearTransform();
                foreach (var g in allg) dc.DrawGeometry(new SolidColorBrush(g.Fill), new Pen(new SolidColorBrush(g.Stroke), Tickness), g.Stream);
                foreach (var g in otherg) dc.DrawGeometry(new SolidColorBrush(g.Fill), new Pen(new SolidColorBrush(g.Stroke), Tickness), g.Stream);
                foreach (var g in myg) dc.DrawGeometry(new SolidColorBrush(g.Fill), new Pen(new SolidColorBrush(g.Stroke), Tickness), g.Stream);
                dc.Close();
            }
        }
        protected System.Threading.CancellationTokenSource CancelTokenSource { get; set; }
        /// <summary>
        /// 生成图形
        /// </summary>
        /// <returns></returns>
        internal abstract Task<List<StreamColor>> GetGeometries(CancellationToken token, IList xSource, IList ySource, IAxis xAxis, IAxis yAxis, IList<int> indexs, Func<object, double> xValueConverter, Func<object, double> yValueConverter, Color fill, Color stroke, Func<long, long, Color> getGradientColor);

        /// <summary>
        /// 移动图形
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        internal virtual void Move(double x, double y)
        {
            Matrix.OffsetX += x;
            Matrix.OffsetY += y;
            MatrixTransform.Matrix = Matrix;
        }
        /// <summary>
        /// 缩放图形
        /// </summary>
        /// <param name="centerX"></param>
        /// <param name="centerY"></param>
        /// <param name="scaleX"></param>
        /// <param name="scaleY"></param>
        //internal virtual void Zoom(Point center, double scaleX, double scaleY)
        //{
        //    Point pointToContent = this.RenderTransform.Inverse.Transform(center);
        //    Matrix.M11 *= scaleX;
        //    Matrix.M22 *= scaleY;

        //    Matrix.OffsetX = -((pointToContent.X * Matrix.M11) - center.X);
        //    Matrix.OffsetY = -((pointToContent.Y * Matrix.M22) - center.Y);
        //    MatrixTransform.Matrix = Matrix;
        //}
        /// <summary>
        /// 清除图形转换
        /// </summary>
        internal virtual void ClearTransform()
        {
            Matrix.M11 = Matrix.M22 = 1;
            Matrix.OffsetX = Matrix.OffsetY = 0;
            MatrixTransform.Matrix = Matrix;
        }
        #endregion

        #region 区域变更

        /// <summary>
        /// 添加区域
        /// </summary>
        /// <param name="area"></param>
        internal abstract void AddArea(Graphical.GraphicalArea area, IList xSource, IList ySource, IAxis xAxis, IAxis yAxis, IList<int> indexs, Func<object, double> xValueConverter, Func<object, double> yValueConverter);
        /// <summary>
        /// 删除区域
        /// </summary>
        /// <param name="area"></param>

        internal abstract void RemoveArea(Graphical.GraphicalArea area);
        /// <summary>
        /// 更新区域显示颜色
        /// </summary>
        /// <param name="area"></param>

        internal abstract void UpdateAreaDisplayColor(Graphical.GraphicalArea area);
        /// <summary>
        /// 更新区域索引
        /// </summary>
        /// <param name="area"></param>
        internal abstract void UpdateAreaIndexs(Graphical.GraphicalArea area, IList xSource, IList ySource, IAxis xAxis, IAxis yAxis, IList<int> indexs, Func<object, double> xValueConverter, Func<object, double> yValueConverter);

        #endregion

        protected override int VisualChildrenCount => 1;
        protected override Visual GetVisualChild(int index)
        {
            return DV;
        }

        /// <summary>
        /// 根据名称创建图
        /// </summary>
        /// <param name="seriesName"></param>
        /// <returns></returns>
        public static ISeries CreateFromSeriesName(string seriesName)
        {
            switch (seriesName)
            {
                case "Histogram":
                    return new HistogramSeries();
                case "Contour":
                    return new ContourSeries();
                case "Density":
                    return new DensitySeries();
                case "Scatter":
                default:
                    return new ScatterSeries();
            }
        }
    }

    public class StreamColor
    {
        public StreamGeometry Stream { get; set; }
        public Color Fill { get; set; }
        public Color Stroke { get; set; }
        public Graphical.GraphicalArea Area { get; set; }
    }
}
